convert garmin_txt to Format class (#1231)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Sun, 19 Nov 2023 00:49:24 +0000 (17:49 -0700)
committerGitHub <noreply@github.com>
Sun, 19 Nov 2023 00:49:24 +0000 (17:49 -0700)
* convert garmin_txt to Format class

* fix includes for qt5

CMakeLists.txt
garmin_txt.cc
garmin_txt.h [new file with mode: 0644]
vecs.cc

index 38f2ff4cdea2f4ce74904c4a097c9143d993b844..3308221d2ad5ba4d9994b3139e233d8ade0e5c2b 100644 (file)
@@ -210,6 +210,7 @@ set(HEADERS
   gbfile.h
   gbser.h
   gbser_private.h
+  garmin_txt.h
   garmin_xt.h
   gdb.h
   geocache.h
index f7b1575fd5ff3f6732f74a114260c2fb21ad41fa..81f5d1b59e97df1a24011dd9e0ca6050c7e86d87 100644 (file)
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
  */
+#if CSVFMTS_ENABLED
 
-#include "defs.h"
+#include "garmin_txt.h"
 
-#if CSVFMTS_ENABLED
 #include <algorithm>               // for for_each, sort
-#include <array>                   // for array
+#include <array>                   // for array, array<>::iterator
 #include <cctype>                  // for toupper
 #include <cmath>                   // for fabs, floor
 #include <cstdint>                 // for uint16_t
 #include <cstdio>                  // for sscanf, fprintf, snprintf, stderr
 #include <cstdlib>                 // for abs
 #include <cstring>                 // for strstr, strlen
-#include <ctime>                   // for time_t, gmtime, localtime, strftime
-#include <optional>                // for optional
-#include <utility>                 // for as_const, pair, make_pair
+#include <ctime>                   // for gmtime, time_t, localtime, strftime, tm
 
+#include <optional>                // for optional
+#include <type_traits>             // for add_const_t
+#include <utility>                 // for pair, as_const, make_pair
 #include <QByteArray>              // for QByteArray
 #include <QChar>                   // for QChar, QChar::Other_Control
 #include <QDateTime>               // for QDateTime
-#include <QIODevice>               // for QIODevice, QIODevice::ReadOnly, QIODevice::WriteOnly
+#include <QDebug>                  // for QDebug
+#include <QIODevice>               // for QIODevice, QIODeviceBase::ReadOnly, QIODeviceBase::WriteOnly
 #include <QList>                   // for QList, QList<>::const_iterator
 #include <QString>                 // for QString, operator!=
 #include <QStringList>             // for QStringList
+#include <QStringLiteral>          // for qMakeStringPrivate, QStringLiteral
 #include <QTextStream>             // for QTextStream
 #include <QVector>                 // for QVector
 #include <Qt>                      // for CaseInsensitive
 #include <QtGlobal>                // for qRound, qPrintable
 
+#include "defs.h"
 #include "csv_util.h"              // for csv_linesplit
 #include "formspec.h"              // for FormatSpecificDataList
 #include "garmin_fs.h"             // for garmin_fs_t
 #include "garmin_tables.h"         // for gt_display_modes_e, gt_find_desc_from_icon_number, gt_find_icon_number_from_desc, gt_get_mps_grid_longname, gt_lookup_datum_index, gt_lookup_grid_type, GDB, gt_get_icao_cc, gt_get_icao_country, gt_get_mps_datum_name, gt_waypt_class_names, GT_DISPLAY_MODE...
 #include "jeeps/gpsmath.h"         // for GPS_Math_Known_Datum_To_UTM_EN, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_Swiss_EN, GPS_Math_WGS84_To_UKOSMap_M
 #include "src/core/datetime.h"     // for DateTime
-#include "src/core/logging.h"      // for Fatal
+#include "src/core/logging.h"      // for FatalMsg
 #include "src/core/textstream.h"   // for TextStream
 
 
 #define MYNAME "garmin_txt"
 
-struct gtxt_flags_t {
-  unsigned int metric:1;
-  unsigned int celsius:1;
-  unsigned int utc:1;
-  unsigned int enum_waypoints:1;
-  unsigned int route_header_written:1;
-  unsigned int track_header_written:1;
-};
-
-static gpsbabel::TextStream* fin = nullptr;
-static gpsbabel::TextStream* fout = nullptr;
-static route_head* current_trk;
-static route_head* current_rte;
-static int waypoints;
-static int routepoints;
-static const Waypoint** wpt_a;
-static int wpt_a_ct;
-static grid_type grid_index;
-static int datum_index;
-static const char* datum_str;
-static int current_line;
-static QString date_time_format;
-static int precision = 3;
-static time_t utc_offs = 0;
-static gtxt_flags_t gtxt_flags;
-
-enum header_type {
-  waypt_header = 0,
-  rtept_header,
-  trkpt_header,
-  route_header,
-  track_header,
-  unknown_header
+const QVector<QString> GarminTxtFormat::headers = {
+  "Name\tDescription\tType\tPosition\tAltitude\tDepth\tProximity\tTemperature\t"
+  "Display Mode\tColor\tSymbol\tFacility\tCity\tState\tCountry\t"
+  "Date Modified\tLink\tCategories",
+  "Waypoint Name\tDistance\tLeg Length\tCourse",
+  "Position\tTime\tAltitude\tDepth\tTemperature\tLeg Length\tLeg Time\tLeg Speed\tLeg Course",
+  "Name\tLength\tCourse\tWaypoints\tLink",
+  "Name\tStart Time\tElapsed Time\tLength\tAverage Speed\tLink"
 };
 
-inline header_type& operator++(header_type& s) // prefix
-{
-  return s = static_cast<header_type>(s + 1);
-}
-inline header_type operator++(header_type& s, int) // postfix
-{
-  header_type ret(s);
-  ++s;
-  return ret;
-}
-
 inline gt_display_modes_e& operator++(gt_display_modes_e& s) // prefix
 {
   return s = static_cast<gt_display_modes_e>(s + 1);
@@ -117,78 +85,22 @@ inline gt_display_modes_e operator++(gt_display_modes_e& s, int) // postfix
   return ret;
 }
 
-static std::array<QList<std::pair<QString, int>>, unknown_header> header_mapping_info;
-static QStringList header_column_names;
-
-static constexpr double kGarminUnknownAlt = 1.0e25;
-static constexpr char kDefaultDateFormat[] = "dd/mm/yyyy";
-static constexpr char kDefaultTimeFormat[] = "HH:mm:ss";
-
-static bool is_valid_alt(double alt)
+bool GarminTxtFormat::is_valid_alt(double alt)
 {
   return (alt != unknown_alt) && (alt < kGarminUnknownAlt);
 }
 
-static char* opt_datum = nullptr;
-static char* opt_dist = nullptr;
-static char* opt_temp = nullptr;
-static char* opt_date_format = nullptr;
-static char* opt_time_format = nullptr;
-static char* opt_precision = nullptr;
-static char* opt_utc = nullptr;
-static char* opt_grid = nullptr;
-
-static
-QVector<arglist_t> garmin_txt_args = {
-  {"date",  &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
-  {"datum", &opt_datum,            "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
-  {"dist",  &opt_dist,        "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
-  {"grid",  &opt_grid,        "Write position using this grid.", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
-  {"prec",  &opt_precision,   "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX, nullptr},
-  {"temp",  &opt_temp,        "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
-  {"time",  &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
-  {"utc",   &opt_utc,         "Write timestamps with offset x to UTC time", nullptr, ARGTYPE_INT, "-23", "+23", nullptr},
-};
-
-class PathInfo
-{
-public:
-  double length {0};
-  time_t start {0};
-  time_t time {0};
-  double speed {0};
-  double total {0};
-  int count {0};
-  const Waypoint* prev_wpt {nullptr};
-  const Waypoint* first_wpt {nullptr};
-  const Waypoint* last_wpt {nullptr};
-};
-
-static PathInfo* route_info;
-static int route_idx;
-static PathInfo* cur_info;
-
-static const QVector<QString> headers = {
-  "Name\tDescription\tType\tPosition\tAltitude\tDepth\tProximity\tTemperature\t"
-  "Display Mode\tColor\tSymbol\tFacility\tCity\tState\tCountry\t"
-  "Date Modified\tLink\tCategories",
-  "Waypoint Name\tDistance\tLeg Length\tCourse",
-  "Position\tTime\tAltitude\tDepth\tTemperature\tLeg Length\tLeg Time\tLeg Speed\tLeg Course",
-  "Name\tLength\tCourse\tWaypoints\tLink",
-  "Name\tStart Time\tElapsed Time\tLength\tAverage Speed\tLink"
-};
-
 /* helpers */
 
-static const char*
-get_option_val(const char* option, const char* def)
+const char*
+GarminTxtFormat::get_option_val(const char* option, const char* def)
 {
   const char* c = (option != nullptr) ? option : def;
   return c;
 }
 
-static void
-init_date_and_time_format()
+void
+GarminTxtFormat::init_date_and_time_format()
 {
   // This is old, and weird, code.. date_time_format is a global that's
   // explicitly malloced and freed elsewhere. This isn't very C++ at all,
@@ -202,8 +114,8 @@ init_date_and_time_format()
   date_time_format = QStringLiteral("%1 %2").arg(d1, t1);
 }
 
-static void
-convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon)
+void
+GarminTxtFormat::convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon) const
 {
   double alt;
 
@@ -218,8 +130,8 @@ convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon)
 
 /* Waypoint preparation */
 
-static void
-enum_waypt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::enum_waypt_cb(const Waypoint* wpt)
 {
   const garmin_fs_t* gmsd = garmin_fs_t::find(wpt);
   int wpt_class = garmin_fs_t::get_wpt_class(gmsd, 0);
@@ -244,21 +156,21 @@ enum_waypt_cb(const Waypoint* wpt)
 
 /* common route and track pre-work */
 
-static void
-prework_hdr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::prework_hdr_cb(const route_head* /*unused*/)
 {
   cur_info = &route_info[route_idx];
 }
 
-static void
-prework_tlr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::prework_tlr_cb(const route_head* /*unused*/)
 {
   cur_info->last_wpt = cur_info->prev_wpt;
   route_idx++;
 }
 
-static void
-prework_wpt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::prework_wpt_cb(const Waypoint* wpt)
 {
   const Waypoint* prev = cur_info->prev_wpt;
 
@@ -277,8 +189,8 @@ prework_wpt_cb(const Waypoint* wpt)
 
 /* output helpers */
 
-static void
-print_position(const Waypoint* wpt)
+void
+GarminTxtFormat::print_position(const Waypoint* wpt)
 {
   int valid = 1;
   double lat, lon, north, east;
@@ -363,8 +275,8 @@ print_position(const Waypoint* wpt)
   }
 }
 
-static void
-print_date_and_time(const time_t time, const bool time_only)
+void
+GarminTxtFormat::print_date_and_time(const time_t time, const bool time_only)
 {
   std::tm tm{};
   char tbuf[32];
@@ -390,8 +302,8 @@ print_date_and_time(const time_t time, const bool time_only)
   *fout << "\t";
 }
 
-static void
-print_categories(uint16_t categories)
+void
+GarminTxtFormat::print_categories(uint16_t categories)
 {
   const QStringList categoryList = garmin_fs_t::print_categories(categories);
   if (!categoryList.isEmpty()) {
@@ -399,8 +311,8 @@ print_categories(uint16_t categories)
   }
 }
 
-static void
-print_course(const Waypoint* A, const Waypoint* B)             /* seems to be okay */
+void
+GarminTxtFormat::print_course(const Waypoint* A, const Waypoint* B)            /* seems to be okay */
 {
   if ((A != nullptr) && (B != nullptr) && (A != B)) {
     int course = qRound(waypt_course(A, B));
@@ -408,8 +320,8 @@ print_course(const Waypoint* A, const Waypoint* B)          /* seems to be okay */
   }
 }
 
-static void
-print_distance(const double distance, const bool no_scale, const bool with_tab, const int decis)
+void
+GarminTxtFormat::print_distance(const double distance, const bool no_scale, const bool with_tab, const int decis)
 {
   double dist = distance;
 
@@ -443,8 +355,8 @@ print_distance(const double distance, const bool no_scale, const bool with_tab,
   }
 }
 
-static void
-print_speed(const double distance, const time_t time)
+void
+GarminTxtFormat::print_speed(const double distance, const time_t time)
 {
   double dist = distance;
   const char* unit;
@@ -474,8 +386,8 @@ print_speed(const double distance, const time_t time)
   *fout << "\t";
 }
 
-static void
-print_temperature(const float temperature)
+void
+GarminTxtFormat::print_temperature(const float temperature)
 {
   if (gtxt_flags.celsius) {
     *fout << QString::asprintf("%.f C", temperature);
@@ -484,8 +396,8 @@ print_temperature(const float temperature)
   }
 }
 
-static void
-print_string(const char* fmt, const QString& string)
+void
+GarminTxtFormat::print_string(const char* fmt, const QString& string)
 {
   /* remove unwanted characters from source string */
   QString cleanstring;
@@ -502,8 +414,8 @@ print_string(const char* fmt, const QString& string)
 
 /* main cb's */
 
-static void
-write_waypt(const Waypoint* wpt)
+void
+GarminTxtFormat::write_waypt(const Waypoint* wpt)
 {
   const char* wpt_type;
 
@@ -588,8 +500,8 @@ write_waypt(const Waypoint* wpt)
   *fout << "\r\n";
 }
 
-static void
-route_disp_hdr_cb(const route_head* rte)
+void
+GarminTxtFormat::route_disp_hdr_cb(const route_head* rte)
 {
   cur_info = &route_info[route_idx];
   cur_info->prev_wpt = nullptr;
@@ -614,14 +526,14 @@ route_disp_hdr_cb(const route_head* rte)
   *fout << QStringLiteral("\r\nHeader\t%1\r\n\r\n").arg(headers[rtept_header]);
 }
 
-static void
-route_disp_tlr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::route_disp_tlr_cb(const route_head* /*unused*/)
 {
   route_idx++;
 }
 
-static void
-route_disp_wpt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::route_disp_wpt_cb(const Waypoint* wpt)
 {
   const Waypoint* prev = cur_info->prev_wpt;
 
@@ -642,8 +554,8 @@ route_disp_wpt_cb(const Waypoint* wpt)
   cur_info->prev_wpt = wpt;
 }
 
-static void
-track_disp_hdr_cb(const route_head* track)
+void
+GarminTxtFormat::track_disp_hdr_cb(const route_head* track)
 {
   cur_info = &route_info[route_idx];
   cur_info->prev_wpt = nullptr;
@@ -669,14 +581,14 @@ track_disp_hdr_cb(const route_head* track)
   *fout << QStringLiteral("\r\n\r\nHeader\t%1\r\n\r\n").arg(headers[trkpt_header]);
 }
 
-static void
-track_disp_tlr_cb(const route_head* /*unused*/)
+void
+GarminTxtFormat::track_disp_tlr_cb(const route_head* /*unused*/)
 {
   route_idx++;
 }
 
-static void
-track_disp_wpt_cb(const Waypoint* wpt)
+void
+GarminTxtFormat::track_disp_wpt_cb(const Waypoint* wpt)
 {
   const Waypoint* prev = cur_info->prev_wpt;
   time_t delta;
@@ -719,8 +631,8 @@ track_disp_wpt_cb(const Waypoint* wpt)
 * %%%        global callbacks called by gpsbabel main process              %%% *
 *******************************************************************************/
 
-static void
-garmin_txt_utc_option()
+void
+GarminTxtFormat::garmin_txt_utc_option()
 {
   if (opt_utc != nullptr) {
     if (case_ignore_strcmp(opt_utc, "utc") == 0) {
@@ -733,16 +645,16 @@ garmin_txt_utc_option()
   }
 }
 
-static void
-garmin_txt_adjust_time(QDateTime& dt)
+void
+GarminTxtFormat::garmin_txt_adjust_time(QDateTime& dt) const
 {
   if (gtxt_flags.utc) {
     dt = dt.toUTC().addSecs(dt.offsetFromUtc() - utc_offs);
   }
 }
 
-static void
-garmin_txt_wr_init(const QString& fname)
+void
+GarminTxtFormat::wr_init(const QString& fname)
 {
   gtxt_flags = {};
 
@@ -790,8 +702,8 @@ garmin_txt_wr_init(const QString& fname)
   garmin_txt_utc_option();
 }
 
-static void
-garmin_txt_wr_deinit()
+void
+GarminTxtFormat::wr_deinit()
 {
   fout->close();
   delete fout;
@@ -800,9 +712,40 @@ garmin_txt_wr_deinit()
   date_time_format.squeeze();
 }
 
-static void
-garmin_txt_write()
+void
+GarminTxtFormat::write()
 {
+  auto enum_waypt_cb_lambda = [this](const Waypoint* waypointp)->void {
+    enum_waypt_cb(waypointp);
+  };
+  auto prework_hdr_cb_lambda = [this](const route_head* rte)->void {
+    prework_hdr_cb(rte);
+  };
+  auto prework_tlr_cb_lambda = [this](const route_head* rte)->void {
+    prework_tlr_cb(rte);
+  };
+  auto prework_wpt_cb_lambda = [this](const Waypoint* waypointp)->void {
+    prework_wpt_cb(waypointp);
+  };
+  auto route_disp_hdr_cb_lambda = [this](const route_head* rte)->void {
+    route_disp_hdr_cb(rte);
+  };
+  auto route_disp_tlr_cb_lambda = [this](const route_head* rte)->void {
+    route_disp_tlr_cb(rte);
+  };
+  auto route_disp_wpt_cb_lambda = [this](const Waypoint* waypointp)->void {
+    route_disp_wpt_cb(waypointp);
+  };
+  auto track_disp_hdr_cb_lambda = [this](const route_head* rte)->void {
+    track_disp_hdr_cb(rte);
+  };
+  auto track_disp_tlr_cb_lambda = [this](const route_head* rte)->void {
+    track_disp_tlr_cb(rte);
+  };
+  auto track_disp_wpt_cb_lambda = [this](const Waypoint* waypointp)->void {
+    track_disp_wpt_cb(waypointp);
+  };
+
   QString grid_str = gt_get_mps_grid_longname(grid_index, MYNAME);
   grid_str = grid_str.replace('*', "°");
   *fout << "Grid\t" << grid_str << "\r\n";
@@ -812,15 +755,15 @@ garmin_txt_write()
 
   waypoints = 0;
   gtxt_flags.enum_waypoints = 1;                       /* enum all waypoints */
-  waypt_disp_all(enum_waypt_cb);
-  route_disp_all(nullptr, nullptr, enum_waypt_cb);
+  waypt_disp_all(enum_waypt_cb_lambda);
+  route_disp_all(nullptr, nullptr, enum_waypt_cb_lambda);
   gtxt_flags.enum_waypoints = 0;
 
   if (waypoints > 0) {
     wpt_a_ct = 0;
     wpt_a = new const Waypoint*[waypoints] {};
-    waypt_disp_all(enum_waypt_cb);
-    route_disp_all(nullptr, nullptr, enum_waypt_cb);
+    waypt_disp_all(enum_waypt_cb_lambda);
+    route_disp_all(nullptr, nullptr, enum_waypt_cb_lambda);
     auto sort_waypt_lambda = [](const Waypoint* wa, const Waypoint* wb)->bool {
       return wa->shortname.compare(wb->shortname, Qt::CaseInsensitive) < 0;
     };
@@ -835,10 +778,11 @@ garmin_txt_write()
     route_idx = 0;
     route_info = new PathInfo[route_count()];
     routepoints = 0;
-    route_disp_all(prework_hdr_cb, prework_tlr_cb, prework_wpt_cb);
+    route_disp_all(prework_hdr_cb_lambda, prework_tlr_cb_lambda, prework_wpt_cb_lambda);
+
     if (routepoints > 0) {
       route_idx = 0;
-      route_disp_all(route_disp_hdr_cb, route_disp_tlr_cb, route_disp_wpt_cb);
+      route_disp_all(route_disp_hdr_cb_lambda, route_disp_tlr_cb_lambda, route_disp_wpt_cb_lambda);
     }
     delete[] route_info;
     route_info = nullptr;
@@ -847,11 +791,11 @@ garmin_txt_write()
   route_idx = 0;
   route_info = new PathInfo[track_count()];
   routepoints = 0;
-  track_disp_all(prework_hdr_cb, prework_tlr_cb, prework_wpt_cb);
+  track_disp_all(prework_hdr_cb_lambda, prework_tlr_cb_lambda, prework_wpt_cb_lambda);
 
   if (routepoints > 0) {
     route_idx = 0;
-    track_disp_all(track_disp_hdr_cb, track_disp_tlr_cb, track_disp_wpt_cb);
+    track_disp_all(track_disp_hdr_cb_lambda, track_disp_tlr_cb_lambda, track_disp_wpt_cb_lambda);
   }
   delete[] route_info;
 }
@@ -860,8 +804,8 @@ garmin_txt_write()
 
 /* helpers */
 
-static void
-free_headers()
+void
+GarminTxtFormat::free_headers()
 {
   std::for_each(header_mapping_info.begin(), header_mapping_info.end(),
                 [](auto& list)->void { list.clear(); });
@@ -870,8 +814,8 @@ free_headers()
 // Super simple attempt to convert strftime/strptime spec to Qt spec.
 // This misses a LOT of cases and vagaries, but the reality is that we
 // see very few date formats here.
-static QString
-strftime_to_timespec(const char* s)
+QString
+GarminTxtFormat::strftime_to_timespec(const char* s)
 {
   QString q;
   int l = strlen(s);
@@ -944,15 +888,15 @@ strftime_to_timespec(const char* s)
 
 /* data parsers */
 
-static QDateTime
-parse_date_and_time(const QString& str)
+QDateTime
+GarminTxtFormat::parse_date_and_time(const QString& str)
 {
   QString timespec = strftime_to_timespec(CSTR(date_time_format));
   return QDateTime::fromString(QString(str).trimmed(), timespec);
 }
 
-static uint16_t
-parse_categories(const QString& str)
+uint16_t
+GarminTxtFormat::parse_categories(const QString& str) const
 {
   uint16_t res = 0;
 
@@ -970,8 +914,8 @@ parse_categories(const QString& str)
   return res;
 }
 
-static bool
-parse_temperature(const QString& str, double* temperature)
+bool
+GarminTxtFormat::parse_temperature(const QString& str, double* temperature) const
 {
   double value;
   unsigned char unit;
@@ -999,8 +943,8 @@ parse_temperature(const QString& str, double* temperature)
   return false;
 }
 
-static void
-parse_header(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_header(const QStringList& lineparts)
 {
   header_column_names.clear();
   for (const auto& name : lineparts) {
@@ -1008,8 +952,8 @@ parse_header(const QStringList& lineparts)
   }
 }
 
-static bool
-parse_display(const QString& str, int* val)
+bool
+GarminTxtFormat::parse_display(const QString& str, int* val) const
 {
   if (str.isEmpty()) {
     return false;
@@ -1025,8 +969,8 @@ parse_display(const QString& str, int* val)
   return false;
 }
 
-static void
-bind_fields(const header_type ht)
+void
+GarminTxtFormat::bind_fields(const header_type ht)
 {
   if ((grid_index < 0) || (datum_index < 0)) {
     fatal(MYNAME ": Incomplete or invalid file header!");
@@ -1058,8 +1002,8 @@ bind_fields(const header_type ht)
   header_column_names.clear();
 }
 
-static void
-parse_grid(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_grid(const QStringList& lineparts)
 {
   if (lineparts.empty()) {
     fatal(MYNAME ": Missing grid headline!\n");
@@ -1078,8 +1022,8 @@ parse_grid(const QStringList& lineparts)
   }
 }
 
-static void
-parse_datum(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_datum(const QStringList& lineparts)
 {
   if (lineparts.empty()) {
     fatal(MYNAME ": Missing GPS datum headline!\n");
@@ -1089,8 +1033,8 @@ parse_datum(const QStringList& lineparts)
   datum_index = gt_lookup_datum_index(CSTR(str), MYNAME);
 }
 
-static void
-parse_waypoint(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_waypoint(const QStringList& lineparts)
 {
   int column = -1;
 
@@ -1197,8 +1141,8 @@ parse_waypoint(const QStringList& lineparts)
   waypt_add(wpt);
 }
 
-static void
-parse_route_header(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_route_header(const QStringList& lineparts)
 {
   int column = -1;
 
@@ -1226,8 +1170,8 @@ parse_route_header(const QStringList& lineparts)
   current_rte = rte;
 }
 
-static void
-parse_track_header(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_track_header(const QStringList& lineparts)
 {
   int column = -1;
 
@@ -1255,8 +1199,8 @@ parse_track_header(const QStringList& lineparts)
 }
 
 
-static void
-parse_route_waypoint(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_route_waypoint(const QStringList& lineparts)
 {
   int column = -1;
   Waypoint* wpt = nullptr;
@@ -1287,8 +1231,8 @@ parse_route_waypoint(const QStringList& lineparts)
   }
 }
 
-static void
-parse_track_waypoint(const QStringList& lineparts)
+void
+GarminTxtFormat::parse_track_waypoint(const QStringList& lineparts)
 {
   int column = -1;
 
@@ -1349,8 +1293,8 @@ parse_track_waypoint(const QStringList& lineparts)
 
 /***************************************************************/
 
-static void
-garmin_txt_rd_init(const QString& fname)
+void
+GarminTxtFormat::rd_init(const QString& fname)
 {
   gtxt_flags = {};
 
@@ -1367,8 +1311,8 @@ garmin_txt_rd_init(const QString& fname)
   garmin_txt_utc_option();
 }
 
-static void
-garmin_txt_rd_deinit()
+void
+GarminTxtFormat::rd_deinit()
 {
   free_headers();
   header_column_names.clear();
@@ -1379,8 +1323,8 @@ garmin_txt_rd_deinit()
   date_time_format.squeeze();
 }
 
-static void
-garmin_txt_read()
+void
+GarminTxtFormat::read()
 {
   QString buff;
 
@@ -1424,27 +1368,4 @@ garmin_txt_read()
 
   }
 }
-
-/*
- * The file encoding is windows-1252.
- * Conversion between windows-1252 and utf-16 is handled by the stream.
- * Conversion between utf-16 and utf-8 is handled by this format.
- * Let main know char strings have already been converted to utf-8
- * so it doesn't attempt to re-convert any char strings including gmsd data.
- */
-
-ff_vecs_t garmin_txt_vecs = {
-  ff_type_file,
-  FF_CAP_RW_ALL,
-  garmin_txt_rd_init,
-  garmin_txt_wr_init,
-  garmin_txt_rd_deinit,
-  garmin_txt_wr_deinit,
-  garmin_txt_read,
-  garmin_txt_write,
-  nullptr,
-  &garmin_txt_args,
-  NULL_POS_OPS
-};
-
 #endif // CSVFMTS_ENABLED
diff --git a/garmin_txt.h b/garmin_txt.h
new file mode 100644 (file)
index 0000000..82346a3
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+
+    Support for MapSource Text Export (Tab delimited) files.
+
+    Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org
+    Copyright (C) 2004-2022 Robert Lipe, robertlipe+source@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ */
+#ifndef GARMIN_TXT_H_INCLUDED_
+#define GARMIN_TXT_H_INCLUDED_
+
+#if CSVFMTS_ENABLED
+
+#include <array>                  // for array
+#include <cstdint>                // for uint16_t
+#include <ctime>                  // for time_t
+#include <utility>                // for pair
+
+#include <QDateTime>              // for QDateTime
+#include <QList>                  // for QList
+#include <QString>                // for QString
+#include <QStringList>            // for QStringList
+#include <QVector>                // for QVector
+
+#include "defs.h"
+#include "format.h"               // for Format
+#include "src/core/textstream.h"  // for TextStream
+
+
+class GarminTxtFormat : public Format
+{
+public:
+  QVector<arglist_t>* get_args() override
+  {
+    return &garmin_txt_args;
+  }
+
+  ff_type get_type() const override
+  {
+    return ff_type_file;
+  }
+
+  QVector<ff_cap> get_cap() const override
+  {
+    return FF_CAP_RW_ALL;
+  }
+
+  void rd_init(const QString& fname) override;
+  void read() override;
+  void rd_deinit() override;
+  void wr_init(const QString& fname) override;
+  void write() override;
+  void wr_deinit() override;
+
+private:
+  /* Constants */
+
+  static constexpr double kGarminUnknownAlt = 1.0e25;
+  static constexpr char kDefaultDateFormat[] = "dd/mm/yyyy";
+  static constexpr char kDefaultTimeFormat[] = "HH:mm:ss";
+
+  static const QVector<QString> headers;
+
+  /* Types */
+
+  struct gtxt_flags_t {
+    unsigned int metric:1;
+    unsigned int celsius:1;
+    unsigned int utc:1;
+    unsigned int enum_waypoints:1;
+    unsigned int route_header_written:1;
+    unsigned int track_header_written:1;
+  };
+
+  enum header_type {
+    waypt_header = 0,
+    rtept_header,
+    trkpt_header,
+    route_header,
+    track_header,
+    unknown_header
+  };
+
+  class PathInfo
+  {
+  public:
+    double length {0};
+    time_t start {0};
+    time_t time {0};
+    double speed {0};
+    double total {0};
+    int count {0};
+    const Waypoint* prev_wpt {nullptr};
+    const Waypoint* first_wpt {nullptr};
+    const Waypoint* last_wpt {nullptr};
+  };
+
+  /* Member Functions */
+
+  static bool is_valid_alt(double alt);
+  static const char* get_option_val(const char* option, const char* def);
+  void init_date_and_time_format();
+  void convert_datum(const Waypoint* wpt, double* dest_lat, double* dest_lon) const;
+  void enum_waypt_cb(const Waypoint* wpt);
+  void prework_hdr_cb(const route_head* unused);
+  void prework_tlr_cb(const route_head* unused);
+  void prework_wpt_cb(const Waypoint* wpt);
+  void print_position(const Waypoint* wpt);
+  void print_date_and_time(time_t time, bool time_only);
+  void print_categories(uint16_t categories);
+  void print_course(const Waypoint* A, const Waypoint* B);
+  void print_distance(double distance, bool no_scale, bool with_tab, int decis);
+  void print_speed(double distance, time_t time);
+  void print_temperature(float temperature);
+  void print_string(const char* fmt, const QString& string);
+  void write_waypt(const Waypoint* wpt);
+  void route_disp_hdr_cb(const route_head* rte);
+  void route_disp_tlr_cb(const route_head* unused);
+  void route_disp_wpt_cb(const Waypoint* wpt);
+  void track_disp_hdr_cb(const route_head* track);
+  void track_disp_tlr_cb(const route_head* unused);
+  void track_disp_wpt_cb(const Waypoint* wpt);
+  void garmin_txt_utc_option();
+  void garmin_txt_adjust_time(QDateTime& dt) const;
+  void free_headers();
+  static QString strftime_to_timespec(const char* s);
+  QDateTime parse_date_and_time(const QString& str);
+  uint16_t parse_categories(const QString& str) const;
+  bool parse_temperature(const QString& str, double* temperature) const;
+  void parse_header(const QStringList& lineparts);
+  bool parse_display(const QString& str, int* val) const;
+  void bind_fields(header_type ht);
+  void parse_grid(const QStringList& lineparts);
+  void parse_datum(const QStringList& lineparts);
+  void parse_waypoint(const QStringList& lineparts);
+  void parse_route_header(const QStringList& lineparts);
+  void parse_track_header(const QStringList& lineparts);
+  void parse_route_waypoint(const QStringList& lineparts);
+  void parse_track_waypoint(const QStringList& lineparts);
+
+  /* Data Members */
+
+  gpsbabel::TextStream* fin = nullptr;
+  gpsbabel::TextStream* fout = nullptr;
+  route_head* current_trk{};
+  route_head* current_rte{};
+  int waypoints{};
+  int routepoints{};
+  const Waypoint** wpt_a{};
+  int wpt_a_ct{};
+  grid_type grid_index{};
+  int datum_index{};
+  const char* datum_str{};
+  int current_line{};
+  QString date_time_format;
+  int precision = 3;
+  time_t utc_offs = 0;
+  gtxt_flags_t gtxt_flags{};
+
+  std::array<QList<std::pair<QString, int>>, unknown_header> header_mapping_info;
+  QStringList header_column_names;
+
+  char* opt_datum = nullptr;
+  char* opt_dist = nullptr;
+  char* opt_temp = nullptr;
+  char* opt_date_format = nullptr;
+  char* opt_time_format = nullptr;
+  char* opt_precision = nullptr;
+  char* opt_utc = nullptr;
+  char* opt_grid = nullptr;
+
+  QVector<arglist_t> garmin_txt_args = {
+    {"date",  &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+    {"datum", &opt_datum,          "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+    {"dist",  &opt_dist,        "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+    {"grid",  &opt_grid,        "Write position using this grid.", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+    {"prec",  &opt_precision,   "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX, nullptr},
+    {"temp",  &opt_temp,        "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+    {"time",  &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
+    {"utc",   &opt_utc,         "Write timestamps with offset x to UTC time", nullptr, ARGTYPE_INT, "-23", "+23", nullptr},
+  };
+
+  PathInfo* route_info{};
+  int route_idx{};
+  PathInfo* cur_info{};
+};
+
+#endif // CSVFMTS_ENABLED
+#endif // GARMIN_TXT_H_INCLUDED_
diff --git a/vecs.cc b/vecs.cc
index a963531f856809363cc133cc4c743bd09861f115..0db4b44adcaf5e540821941e6dd731a45792c093 100644 (file)
--- a/vecs.cc
+++ b/vecs.cc
@@ -46,6 +46,7 @@
 #include "garmin.h"            // for GarminFormat
 #include "garmin_fit.h"        // for GarminFitFormat
 #include "garmin_gpi.h"        // for GarminGPIFormat
+#include "garmin_txt.h"        // for GarminTxtFormat
 #include "garmin_xt.h"         // for GarminXTFormat
 #include "gbversion.h"         // for WEB_DOC_DIR
 #include "gdb.h"               // for GdbFormat
 extern ff_vecs_t geo_vecs;
 extern ff_vecs_t ozi_vecs;
 #if MAXIMAL_ENABLED
-extern ff_vecs_t gpl_vecs;
 extern ff_vecs_t mtk_vecs;
 extern ff_vecs_t mtk_fvecs;
 extern ff_vecs_t mtk_m241_vecs;
 extern ff_vecs_t mtk_m241_fvecs;
 #endif // MAXIMAL_ENABLED
-#if MAXIMAL_ENABLED
-#if CSVFMTS_ENABLED
-extern ff_vecs_t garmin_txt_vecs;
-#endif // CSVFMTS_ENABLED
-extern ff_vecs_t ggv_log_vecs;
-#endif // MAXIMAL_ENABLED
 
 #define MYNAME "vecs"
 
@@ -138,7 +132,7 @@ struct Vecs::Impl {
   UnicsvFormat unicsv_fmt;
   GtmFormat gtm_fmt;
 #if CSVFMTS_ENABLED
-  LegacyFormat garmin_txt_fmt {garmin_txt_vecs};
+  GarminTxtFormat garmin_txt_fmt;
 #endif // CSVFMTS_ENABLED
   GtrnctrFormat gtc_fmt;
   GarminGPIFormat garmin_gpi_fmt;